#include <iostream>
#include <cstdio>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>

#define CREAT IPC_CREAT|IPC_EXCL|0666
#define GET IPC_CREAT

const char* gPathName = "/home";
const int pro_id = 0x66;//至少包含8个bit位
const int gSize = 128;//共享内存的大小

enum{
    FTOK_FAILD = 0,
    SHMGET_FAILD,
    SHMCTL_FAILD,
    SHMDT_FAILD,
    SHMAT_FAILD
};
class Shm
{
public:
    Shm() :_shmid(0), _shmAddress(nullptr),_size(gSize)
    {}
    ~Shm(){}
    //创建--服务端
    void buildShm()
    {
        shmFlag(CREAT);
    }
    //获取--客户端
    void getShm()
    {
        shmFlag(GET);
    }
    //挂载
    void attach()
    {
        _shmAddress = shmat(_shmid, nullptr, 0);
        if((long int)_shmAddress == -1)
        {
            perror("shmat");
            exit(SHMAT_FAILD);
        }
    }
    //解载
    void detach()
    {
        int n = shmdt(_shmAddress);
        if(n < 0)
        {
            perror("shmdt");
            exit(SHMDT_FAILD);
        }
    }
    //删除
    void deleteShm()
    {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if(n < 0)
        {
            perror("shmctl");
            exit(SHMCTL_FAILD);
        }
    }
    void* get_address()
    {
        return _shmAddress;
    }
    int getSize()
    {
        return _size;
    }
    void getStruct()
    {
        struct shmid_ds buffer;
        int n = shmctl(_shmid, IPC_STAT, &buffer);
        if(n < 0)
        {
            perror("shmctl");
            exit(SHMCTL_FAILD);
        }
        std::cout << buffer.shm_nattch << std::endl;
    }

private:
    void shmFlag(int Flag)
    {
        umask(0);//设置权限掩码
        key_t key = getKey();
        _shmid = shmget(key, gSize, Flag);//底层使用的是位图
        if(_shmid < 0)
        {
            perror("shmid");
            exit(SHMGET_FAILD);
        }
    }
    key_t getKey()
    {
        key_t key = ftok(gPathName, pro_id);
        if(key < 0)
        {
            perror("ftok");
            exit(FTOK_FAILD);
        }
        printf("key:%x\n", key);
        return key;
    }

private:
    int _shmid;
    void* _shmAddress;
    int _size;
};

